import data from "../../../../core/cache_data";
import { Library } from "../../../../core/library";
import Utils, { Uid, VectorHelper } from "../../../../core/utils";
import CCCharacter from "../../../eggy/cc_game/cc_character";
import { GameUtils } from "../../../eggy/game_utils";
import { Network } from "../../../net/network";
import { ProtocolC2SGetTotalMsg, ProtocolC2STickMsg, ProtocolC2STotalMsg, ProtocolObjectRoom, ProtocolS2CTickMsg, ProtocolS2CTotalMsg, ProtocolS2CUpdateRoom } from "../../../net/protocol_dist";
import { User } from "../../../net/user";
import CCObject, { ArrData, IOwnerShipObject } from "../../../eggy/cc_game/cc_object";
import BubbleFace from "./bubble_face";
import QuickTalk, { QuickTalkConfig, QuickTalkItemConfig } from "./quick_talk";
import Stick from "./stick";
import CCTestBall from "../../cc_game/cc_test_ball";
import { ILobbyTickData, ILobbyTotalData } from "./page_lobby_game_msg";

const { ccclass, property } = cc._decorator;
@ccclass
export default class PageLobbyGame extends cc.Component {
    @property(Stick)
    stick: Stick = null;

    @property(cc.Label)
    lbCount: cc.Label = null;

    @property(cc.Prefab)
    quickTalkPrefab: cc.Prefab = null;
    @property(cc.Prefab)
    bubbleFace: cc.Prefab = null;
    @property(cc.Prefab)
    ballPrefab: cc.Prefab = null;

    @property(cc.Label)
    lbDebug: cc.Label = null;

    @property(cc.Node)
    root: cc.Node = null;
    ccObjList: CCObject[] = [];
    ccCharList: CCCharacter[] = [];
    _player: CCCharacter = null;
    get player() {
        if (!cc.isValid(this._player)) {
            this._player = this.ccCharList.find(ccChar => {
                return ccChar && ccChar.owner === User.userId;
            });
        }
        return this._player;
    }

    room: ProtocolObjectRoom = null;

    _curTickMsg: ILobbyTickData = null;
    get curTickMsg() {
        if (!this._curTickMsg) {
            this._curTickMsg = {};
        }
        return this._curTickMsg;
    }

    protected onEnable(): void {
        Network.AddListener(ProtocolS2CTickMsg, this.onTickMsg, this);
        Network.AddListener(ProtocolS2CTotalMsg, this.onTotalMsg, this);
        Network.AddListener(ProtocolS2CUpdateRoom, this.onUpdateRoom, this);
        this.schedule(this.scheSendTickMsg, 0.1);
        this.schedule(this.scheSendTotalMsg, 4);
        this.stick.on("move", this.onStickMove, this);
        this.stick.on("stop", this.onStickStop, this);
    }
    onStickMove(pcV2: cc.Vec2) {
        if (this.player) {
            this.player.walk(pcV2);
            this.curTickMsg.eggyMove = [
                this.player.objUid,
                Math.floor(pcV2.x * 100),
                Math.floor(pcV2.y * 100)
            ];
        }
    }
    onStickStop() {
        if (this.player) {
            this.player.stop();
            CreateArrayMember(this.curTickMsg, "eggyMovement");
            this.curTickMsg.eggyMovement.push([
                this.player.objUid,
                "stop",
                Math.floor(this.player.node.x),
                Math.floor(this.player.node.y),
            ]);
        }
    }
    onClickFaceMenu() {
        let qt = cc.instantiate(this.quickTalkPrefab).getComponent(QuickTalk);
        qt.setData(Library.GetRecord(QuickTalkConfig, "quick_talk_face"));
        this.node.addChild(qt.node);
        qt.once("talk", (itemConf: QuickTalkItemConfig) => {
            CreateArrayMember(this.curTickMsg, "eggyMovement");
            this.curTickMsg.eggyMovement.push([
                this.player.objUid,
                "face",
                itemConf.face
            ]);
            this._addFace(this.player, itemConf.face);
        }, this);
    }
    onClickBall() {
        let dv = this.player.dv.normalize().mul(400);
        CreateArrayMember(this.curTickMsg, "addObj");
        this.curTickMsg.addObj.push(CCTestBall.NewLobbyData(
            "ball",
            User.userId,
            this.player.node.x,
            this.player.node.y,
            Math.floor(dv.x),
            Math.floor(dv.y),
            999
        ));
    }
    onClickGrabDrop() {
        if (!this.player) {
            return;
        }
        if (this.player.grabObj) {
            CreateArrayMember(this.curTickMsg, "eggyMovement");
            this.curTickMsg.eggyMovement.push([
                this.player.objUid,
                "drop",
            ]);
        }
        else {
            let wp = this.player.node.convertToWorldSpaceAR(cc.Vec2.ZERO);
            for (let i = 0; i < this.ccObjList.length; i++) {
                let ccObj = this.ccObjList[i];
                if (ccObj.node.convertToWorldSpaceAR(cc.Vec2.ZERO).sub(wp).len() < 200) {
                    CreateArrayMember(this.curTickMsg, "eggyMovement");
                    this.curTickMsg.eggyMovement.push([
                        this.player.objUid,
                        "grab",
                        ccObj.objUid,
                    ]);
                }
            }
        }
    }
    onClickAttack() {
        this.player.attack();
        CreateArrayMember(this.curTickMsg, "eggyMovement");
        this.curTickMsg.eggyMovement.push([
            this.player.objUid,
            "attack"
        ]);
    }
    protected onDisable(): void {
        Network.TargetOff(this);
        this.unscheduleAllCallbacks();
    }
    onUpdateRoom(msg: ProtocolS2CUpdateRoom) {
        this.room = msg.room;
        this.lbCount.string = `${this.room.userList.length}`;
    }
    scheSendTickMsg(dt: number) {
        if (this._curTickMsg) {
            let msg = new ProtocolC2STickMsg();
            msg.time = Date.now();
            msg.data = JSON.stringify(this.curTickMsg);
            msg.echo = true; //分发给发送者
            Network.Send(msg);
            this._curTickMsg = null;
        }
    }
    scheSendTotalMsg(dt: number) {
        if (!this.ownRoom()) {
            return;
        }
        let totalData: ILobbyTotalData = {
            ccCharList: [],
            ccObjList: [],
        };

        this.ccCharList.forEach(ccChar => {
            totalData.ccCharList.push(ccChar.toArrData());
        });
        this.ccObjList.forEach(ccObj => {
            totalData.ccObjList.push(ccObj.toArrData());
        });
        let msg = new ProtocolC2STotalMsg();
        msg.time = Date.now();
        msg.echo = false; //不分发给发送者
        msg.data = JSON.stringify(totalData);
        Network.Send(msg);
    }
    onTickMsg(msg: ProtocolS2CTickMsg) {
        let tick: ILobbyTickData = JSON.parse(msg.data);

        console.log("tick:", tick);

        if (tick.addObj) {
            for (let i = 0; i < tick.addObj.length; i++) {
                this._addObj(tick.addObj[i]);
            }
        }
        if (tick.delObj) {
            for (let i = 0; i < tick.delObj.length; i++) {
                this._delObj(tick.delObj[i]);
            }
        }

        if (tick.addEggy) {
            for (let i = 0; i < tick.addEggy.length; i++) {
                this._addEggy(tick.addEggy[i]);
            }
        }
        if (tick.delEggy) {
            for (let i = 0; i < tick.delEggy.length; i++) {
                this._delEggy(tick.delEggy[i]);
            }
        }
        if (tick.eggyMove) {
            let [uid, x100, y100] = tick.eggyMove;
            let ccChar = this.ccCharList.find(ccChar => !this.ownership(ccChar) && ccChar.objUid === uid);
            if (ccChar) {
                ccChar.walk(cc.v2(x100 / 100, y100 / 100));
            }
        }
        if (tick.eggyMovement) {
            for (let i = 0; i < tick.eggyMovement.length; i++) {
                let [uid, type, x100, y100] = tick.eggyMovement[i];
                let ccChar = this.ccCharList.find(ccChar => ccChar.objUid === uid);
                if (ccChar) {
                    switch (type) {
                        case "stop":
                            if (!this.ownership(ccChar)) {
                                ccChar.stop();
                                ccChar.node.x = x100;
                                ccChar.node.y = y100;
                            }
                            break;
                        case "attack":
                            if (!this.ownership(ccChar)) {
                                ccChar.attack();
                            }
                            break;
                        case "face":
                            if (!this.ownership(ccChar)) {
                                this._addFace(ccChar, x100);
                            }
                            break;
                    }
                    switch (type) {
                        case "grab":
                            {
                                let [_0, _1, targetUid] = tick.eggyMovement[i];
                                let ccChar = this.ccCharList.find(ccChar => ccChar.objUid == uid);
                                let ccObj = this.ccObjList.find(ccObj => ccObj.objUid == targetUid);
                                if (ccObj.owner == User.userId) {
                                    CreateArrayMember(this.curTickMsg, "result");
                                    if (ccChar && ccObj) {
                                        ccObj.owner = ccChar.owner;
                                        this.curTickMsg.result.push([
                                            uid,
                                            type,
                                            true,
                                            targetUid
                                        ]);
                                        this.lbDebug.string += "mm: grab，成功，发送RES\n";
                                    }
                                    else {
                                        this.curTickMsg.result.push([
                                            uid,
                                            type,
                                            false,
                                            targetUid
                                        ])
                                        this.lbDebug.string += "mm: grab，失败，发送RES\n";
                                    }
                                }
                            }
                            break;
                        case "drop":
                            {
                                let ccChar = this.ccCharList.find(ccChar => ccChar.objUid == uid);
                                ccChar.drop();
                                this.lbDebug.string += "收到drop信息，成功\n";
                            }
                            break;
                    }
                }
            }
        }
        if (tick.result) {
            for (let i = 0; i < tick.result.length; i++) {
                let [uid, type, isOk] = tick.result[i];
                switch (type) {
                    case "grab":
                        {
                            this.lbDebug.string += "res: grab\n";
                            let [uid, type, isOk, targetUid] = tick.result[i];
                            if (isOk) {
                                let ccChar = this.ccCharList.find(ccChar => ccChar.objUid == uid);
                                let ccObj = this.ccObjList.find(obj => obj.objUid == targetUid);
                                if (ccChar && ccObj) {
                                    ccChar.grab(ccObj);
                                }
                            }
                        }
                        break;
                }
            }
        }
    }
    onTotalMsg(msg: ProtocolS2CTotalMsg) {
        if (!msg.data) {
            console.log("房间数据空");
            return;
        }
        let total: ILobbyTotalData = JSON.parse(msg.data);

        let delList = [];
        this.ccCharList.forEach(ccChar => {
            if (!total.ccCharList.find(ld => ld[2] === ccChar.objUid)) {
                delList.push(ccChar.objUid);
            }
        });
        delList.forEach(objUid => {
            let ind = this.ccCharList.findIndex(ccChar => ccChar.objUid == objUid)
            this.ccCharList.splice(ind, 1)[0].node.destroy();
        });

        total.ccCharList.forEach(ld => {
            let objUid = ld[2];

            let ccChar = this.ccCharList.find(ccChar => ccChar.objUid === objUid);
            if (!ccChar) {
                ccChar = this._addEggy(ld);
            }
            else {
                ccChar.fromArrData(ld);
            }
        });

        this.ccObjList.forEach(ccObj => {
            if (!total.ccObjList.find(ld => ld[2] === ccObj.objUid)) {
                delList.push(ccObj.objUid);
            }
        });
        delList.forEach(objUid => {
            let ind = this.ccObjList.findIndex(ccObj => ccObj.objUid === objUid)
            this.ccObjList.splice(ind, 1)[0].node.destroy();
        });

        total.ccObjList.forEach(ld => {
            let uuid = ld[2];

            let ccObj = this.ccObjList.find(ccObj => ccObj.objUid === uuid);
            if (!ccObj) {
                ccObj = this._addObj(ld);
            }
            else {
                ccObj.fromArrData(ld);
            }
        });
    }
    async onLoad() {
        this.room = User.room;
        this.lbCount.string = `${this.room.userList.length}`;

        Utils.blocker.show();
        let msg = new ProtocolC2SGetTotalMsg();
        let rtn = await Network.SendAndWaitRecv(msg, ProtocolS2CTotalMsg);
        Utils.blocker.hide();
        if (rtn) {
            console.log("获取房间数据成功");
            this.onTotalMsg(rtn);
            //todo:
        }
        else {
            console.warn("获取房间数据失败");
        }

        if (!this.player) {
            console.warn("没有角色数据，创建角色");
            //进入房间，创建一个自己的角色。
            let charData: ArrData = data.cache.get("char", null);
            CreateArrayMember(this.curTickMsg, "addEggy");
            this.curTickMsg.addEggy.push(charData);
        }
        else {
            console.warn("已有角色数据");
        }

    }
    ownRoom() {
        return this.room.owner === User.userId;
    }
    //是否拥有某物
    //是否房主
    ownership(obj: IOwnerShipObject) {
        return obj && obj.owner === User.userId;
    }
    onObjDie(ccObj: CCObject) {
        CreateArrayMember(this.curTickMsg, "delObj");
        this.curTickMsg.delObj.push(ccObj.objUid);
    }
    protected _addObj(data: ArrData) {
        let ccObj = GameUtils.InstantiateCCGameCom(data[0], CCObject);
        this.ccObjList.push(ccObj);
        ccObj.on("die", this.onObjDie, this);
        ccObj.fromArrData(data);
        this.root.addChild(ccObj.node);
        return ccObj;
    }
    protected _delObj(uid: string) {
        let ind = this.ccObjList.findIndex(ccObj => ccObj.objUid === uid);
        if (ind !== -1) {
            let ccObj = this.ccObjList.splice(ind, 1)[0];
            ccObj.node.destroy();
        }
    }
    protected _addEggy(data: ArrData) {
        let ccChar = GameUtils.InstantiateCCGameCom(data[0], CCCharacter);
        this.root.addChild(ccChar.node);
        ccChar.fromArrData(data);
        this.ccCharList.push(ccChar);
        return ccChar;
    }
    protected _delEggy(uid: string) {
        let ind = this.ccCharList.findIndex(ccChar => ccChar.character.uuid === uid);
        if (ind !== -1) {
            let ccChar = this.ccCharList.splice(ind, 1)[0];
            ccChar.node.destroy();
        }
    }
    _addFace(ccChar: CCCharacter, face: string) {
        let bf = cc.instantiate(this.bubbleFace).getComponent(BubbleFace);
        ccChar.node.addChild(bf.node);
        bf.node.setPosition(80, 120);
        bf.set(face, 2);
    }

    protected update(dt: number): void {
        this.root.children.forEach(child => {
            child.zIndex = 9000 - child.y;
        });

        if (this.player) {
            this.root.x = -this.player.node.x;
            this.root.y = -this.player.node.y;
        }
    }
};

const CreateArrayMember = function (obj: any, memberName: string) {
    if (undefined === obj[memberName] || null === obj[memberName]) {
        obj[memberName] = [];
    }
}